package uk.co.q3c.deplan.server.unit.service;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.List;

import org.apache.log4j.Logger;
import org.testng.Assert;
import org.testng.annotations.Test;

import uk.co.q3c.deplan.client.domain.DomainObject;
import uk.co.q3c.deplan.client.domain.dag.ChangeInvalidException;
import uk.co.q3c.deplan.client.domain.dag.CycleDetectedException;
import uk.co.q3c.deplan.client.domain.resource.DefaultWorkingTime;
import uk.co.q3c.deplan.client.domain.resource.IndividualResource;
import uk.co.q3c.deplan.client.domain.resource.PersistenceReferenceException;
import uk.co.q3c.deplan.client.domain.resource.Resource;
import uk.co.q3c.deplan.client.domain.resource.ResourceAssignmentException;
import uk.co.q3c.deplan.client.domain.resource.ResourcePool;
import uk.co.q3c.deplan.client.domain.task.BaseTask;
import uk.co.q3c.deplan.client.domain.task.Task;
import uk.co.q3c.deplan.client.domain.task.TaskAnalysisResult;
import uk.co.q3c.deplan.client.domain.task.TaskStatusReport;
import uk.co.q3c.deplan.server.dao.Model;
import uk.co.q3c.deplan.server.service.Leveller;
import uk.co.q3c.deplan.server.unit.domain.task.DomainBase_UT;
import uk.co.q3c.deplan.server.util.Q3Calendar;

/**
 * Tests {@link Leveller}
 * 
 * @see Leveller_Bug_Test_1
 * @author DSowerby 3 Aug 2008 21:15:33
 * 
 */
@Test
public class Leveller_UT extends DomainBase_UT {
	protected final Logger logger = Logger.getLogger(getClass().getName());
	Leveller leveller;
	BaseTask task1;
	BaseTask task11;
	BaseTask task12;
	BaseTask task111;
	BaseTask task2;
	BaseTask task21;
	BaseTask task22;
	BaseTask task211;
	BaseTask task2111;
	BaseTask task3;
	BaseTask task4;
	BaseTask task5;
	Resource resources[] = new Resource[7];
	DefaultWorkingTime dwt = new DefaultWorkingTime();
	SimpleDateFormat sdf = new SimpleDateFormat("dd MMM yy HH:mm:ss");
	SimpleDateFormat sdf2 = new SimpleDateFormat("dd MMM yy");

	String testDb = "/home/dave/temp/deplan/leveller_test.db4o";
	ResourcePool resourcePool;

	@Override
	protected void beforeMethod() throws Exception {
		super.beforeMethod();
		Model.setConnection(connection);
		buildPlan();
		buildResources();
		assignResources();
		leveller = new Leveller(connection);
		connection.openSession();
		connection.closeSession();
		leveller.setResourcePool(resourcePool);
	}

	/**
	 * Set of tasks all with the same resource, but in priority order, 100 percent resource allocation.
	 * 
	 * @throws PersistenceReferenceException
	 */
	public void levelPriorityOnly100Percent() throws PersistenceReferenceException {
		BaseTask task1 = createAbstractTask("t1");
		BaseTask task2 = createAbstractTask("t2");
		BaseTask task3 = createAbstractTask("t3");
		BaseTask task4 = createAbstractTask("t4");
		BaseTask task5 = createAbstractTask("t5");

		leveller.addCandidate(task1);
		leveller.addCandidate(task2);
		leveller.addCandidate(task3);
		leveller.addCandidate(task4);
		leveller.addCandidate(task5);

		task1.assignResource(resources[0], 1);
		task2.assignResource(resources[0], 1);
		task3.assignResource(resources[0], 1);
		task4.assignResource(resources[0], 1);
		task5.assignResource(resources[0], 1);

		task4.setPriority(2000);
		task1.setPriority(1999);
		task3.setPriority(1400);
		task2.setPriority(1100);
		task5.setPriority(300);

		task4.setWorkRemaining(1000);
		task1.setWorkRemaining(1000);
		task3.setWorkRemaining(1000);
		task2.setWorkRemaining(1000);
		task5.setWorkRemaining(1000);

		Calendar cal = new GregorianCalendar();
		cal.set(2008, 4, 5);
		leveller.setLevelDate(cal.getTime());
		// ((IndividualResource) resources[0]).setProfile(leveller.getLevelDate(), 100);

		leveller.level();
		logger.info("task4 start: " + task4.getStart() + " plannedFinish:" + task4.getPlannedFinish());
		logger.info("task1 start: " + task1.getStart() + " plannedFinish:" + task1.getPlannedFinish());
		logger.info("task3 start: " + task3.getStart() + " plannedFinish:" + task3.getPlannedFinish());
		logger.info("task2 start: " + task2.getStart() + " plannedFinish:" + task2.getPlannedFinish());
		logger.info("task5 start: " + task5.getStart() + " plannedFinish:" + task5.getPlannedFinish());
		Assert.assertTrue(task4.getStart()
				.before(task1.getStart()));
		Assert.assertTrue(task1.getStart()
				.before(task3.getStart()));
		Assert.assertTrue(task3.getStart()
				.before(task2.getStart()));
		Assert.assertTrue(task2.getStart()
				.before(task5.getStart()));

		Assert.assertTrue(task4.getPlannedFinish()
				.before(task1.getStart()));
		Assert.assertTrue(task1.getPlannedFinish()
				.before(task3.getStart()));
		Assert.assertTrue(task3.getPlannedFinish()
				.before(task2.getStart()));
		Assert.assertTrue(task2.getPlannedFinish()
				.before(task5.getStart()));

		// check precise timings
		Assert.assertEquals(task4.getStart()
				.toString(), "Mon May 05 09:00:00 BST 2008");
		Assert.assertEquals(task4.getPlannedFinish()
				.toString(), "Wed May 07 10:39:00 BST 2008");

		Assert.assertEquals(task1.getStart()
				.toString(), "Wed May 07 10:40:00 BST 2008");
		Assert.assertEquals(task1.getPlannedFinish()
				.toString(), "Fri May 09 12:19:00 BST 2008");

		Assert.assertEquals(task3.getStart()
				.toString(), "Fri May 09 12:20:00 BST 2008");
		Assert.assertEquals(task3.getPlannedFinish()
				.toString(), "Tue May 13 14:29:00 BST 2008");

		Assert.assertEquals(task2.getStart()
				.toString(), "Tue May 13 14:30:00 BST 2008");
		Assert.assertEquals(task2.getPlannedFinish()
				.toString(), "Thu May 15 16:09:00 BST 2008");
	}

	/**
	 * Set of tasks all with the same resource, but in priority order, 100 percent resource allocation.
	 * 
	 * @throws PersistenceReferenceException
	 */
	public void levelPriorityOnlyNot100Percent() throws PersistenceReferenceException {
		BaseTask task1 = createAbstractTask("t1");
		BaseTask task2 = createAbstractTask("t2");
		BaseTask task3 = createAbstractTask("t3");
		BaseTask task4 = createAbstractTask("t4");
		BaseTask task5 = createAbstractTask("t5");

		leveller.addCandidate(task1);
		leveller.addCandidate(task2);
		leveller.addCandidate(task3);
		leveller.addCandidate(task4);
		leveller.addCandidate(task5);

		task1.assignResource(resources[0], 1);
		task2.assignResource(resources[0], 1);
		task3.assignResource(resources[0], 1);
		task4.assignResource(resources[0], 0.5);
		task5.assignResource(resources[0], 1);

		task4.setPriority(2000);
		task1.setPriority(1999);
		task3.setPriority(1400);
		task2.setPriority(1100);
		task5.setPriority(300);

		int wr = 1000;
		task1.setWorkRemaining(wr);
		task2.setWorkRemaining(wr);
		task3.setWorkRemaining(wr);
		task4.setWorkRemaining(wr);
		task5.setWorkRemaining(wr);

		Calendar cal = new GregorianCalendar();
		cal.set(2008, 4, 5);
		leveller.setLevelDate(cal.getTime());
		// ((IndividualResource) resources[0]).setProfile(leveller.getLevelDate(), 100);
		leveller.level();

		logger.info(">>>>>>>>>>>>>>>>. not 100 percent <<<<<<<<<<");
		logger.info("task4 start: " + task4.getStart() + " plannedFinish:" + task4.getPlannedFinish());
		logger.info("task1 start: " + task1.getStart() + " plannedFinish:" + task1.getPlannedFinish());
		logger.info("task3 start: " + task3.getStart() + " plannedFinish:" + task3.getPlannedFinish());
		logger.info("task2 start: " + task2.getStart() + " plannedFinish:" + task2.getPlannedFinish());
		logger.info("task5 start: " + task5.getStart() + " plannedFinish:" + task5.getPlannedFinish());
		Assert.assertTrue(task4.getStart()
				.before(task1.getStart()));
		Assert.assertTrue(task1.getStart()
				.before(task3.getStart()));
		Assert.assertTrue(task3.getStart()
				.before(task2.getStart()));
		Assert.assertTrue(task2.getStart()
				.before(task5.getStart()));

		// check precise timings
		Assert.assertEquals(task4.getStart()
				.toString(), "Mon May 05 09:00:00 BST 2008");
		Assert.assertEquals(task4.getPlannedFinish()
				.toString(), "Fri May 09 10:39:00 BST 2008");

		Assert.assertEquals(task1.getStart()
				.toString(), "Mon May 05 12:45:00 BST 2008");
		Assert.assertEquals(task1.getPlannedFinish()
				.toString(), "Fri May 09 12:19:00 BST 2008");

		Assert.assertEquals(task3.getStart()
				.toString(), "Fri May 09 12:20:00 BST 2008");
		Assert.assertEquals(task3.getPlannedFinish()
				.toString(), "Tue May 13 14:29:00 BST 2008");

		Assert.assertEquals(task2.getStart()
				.toString(), "Tue May 13 14:30:00 BST 2008");
		Assert.assertEquals(task2.getPlannedFinish()
				.toString(), "Thu May 15 16:09:00 BST 2008");
	}

	/**
	 * Set of tasks all with the same resource, but with predecessors preventing natural priority order.
	 * 
	 * @throws PersistenceReferenceException
	 */
	public void levelDependenciesAndPriority() throws PersistenceReferenceException {
		BaseTask task1 = createAbstractTask("t1");
		BaseTask task2 = createAbstractTask("t2");

		task1.assignResource(resources[0], 1);
		task2.assignResource(resources[1], 1);

		task1.setPriority(1999);
		task2.setPriority(1100);
		task1.addPredecessor(task2);

		task1.setWorkRemaining(1000);
		task2.setWorkRemaining(1000);

		leveller.addCandidate(task1);
		leveller.addCandidate(task2);

		Calendar cal = new GregorianCalendar();
		cal.set(2008, 4, 5);

		leveller.setLevelDate(cal.getTime());
		// ((IndividualResource) resources[0]).setProfile(leveller.getLevelDate(), 100);
		leveller.level();

		logger.info(">>>>>>>>>>>>>>>>. levelDependenciesAndPriority <<<<<<<<<<");
		logger.info("task1 start: " + task1.getStart() + " plannedFinish:" + task1.getPlannedFinish());
		logger.info("task2 start: " + task2.getStart() + " plannedFinish:" + task2.getPlannedFinish());
		// task2 will complete as though it were highest priority, because task1
		// depends on it
		Assert.assertEquals(task2.getStart()
				.toString(), "Mon May 05 09:00:00 BST 2008");
		Assert.assertEquals(task2.getPlannedFinish()
				.toString(), "Wed May 07 10:39:00 BST 2008");

		// task1 will start immediately after task2
		// @TODO there is a limitation in the current version which doesn't take
		// into account the time when starting a task after a dependency. Live
		// with
		// that for now, so this checks just for the correct day.
		// Assert.assertEquals(task1.getStart().toString(), "Wed May 07 10:40:00
		// BST
		// 2008");
		// Assert.assertEquals(task1.getFinish().toString(), "Fri May 09
		// 12:19:00
		// BST 2008");
		Assert.assertEquals(sdf2.format(task1.getStart()), "07 May 08");
		Assert.assertEquals(sdf2.format(task1.getPlannedFinish()), "09 May 08");
	}

	/**
	 * Set of tasks with unique resources should all complete in parallel regardless of priority
	 * 
	 * @throws PersistenceReferenceException
	 */
	public void parallelTasks() throws PersistenceReferenceException {
		BaseTask task1 = createAbstractTask("t1");
		BaseTask task2 = createAbstractTask("t2");
		BaseTask task3 = createAbstractTask("t3");
		BaseTask task4 = createAbstractTask("t4");
		BaseTask task5 = createAbstractTask("t5");

		leveller.addCandidate(task1);
		leveller.addCandidate(task2);
		leveller.addCandidate(task3);
		leveller.addCandidate(task4);
		leveller.addCandidate(task5);

		task1.assignResource(resources[0], 1);
		task2.assignResource(resources[1], 1);
		task3.assignResource(resources[2], 1);
		task4.assignResource(resources[3], 1);
		task5.assignResource(resources[4], 1);

		task4.setPriority(2000);
		task1.setPriority(1999);
		task3.setPriority(1400);
		task2.setPriority(1100);
		task5.setPriority(300);

		int wr = 1000;
		task1.setWorkRemaining(wr);
		task2.setWorkRemaining(wr);
		task3.setWorkRemaining(wr);
		task4.setWorkRemaining(wr);
		task5.setWorkRemaining(wr);

		Calendar cal = new GregorianCalendar();
		cal.set(2008, 4, 5);
		leveller.setLevelDate(cal.getTime());
		leveller.level();

		logger.info(">>>>>>>>>>>>>>>>. parallel tasks <<<<<<<<<<");
		logger.info("task4 start: " + task4.getStart() + " plannedFinish:" + task4.getPlannedFinish());
		logger.info("task1 start: " + task1.getStart() + " plannedFinish:" + task1.getPlannedFinish());
		logger.info("task3 start: " + task3.getStart() + " plannedFinish:" + task3.getPlannedFinish());
		logger.info("task2 start: " + task2.getStart() + " plannedFinish:" + task2.getPlannedFinish());
		logger.info("task5 start: " + task5.getStart() + " plannedFinish:" + task5.getPlannedFinish());
		// check precise timings
		Assert.assertEquals(task4.getStart()
				.toString(), "Mon May 05 09:00:00 BST 2008");
		Assert.assertEquals(task4.getPlannedFinish()
				.toString(), "Wed May 07 10:39:00 BST 2008");

		Assert.assertEquals(task1.getStart()
				.toString(), "Mon May 05 09:00:00 BST 2008");
		Assert.assertEquals(task1.getPlannedFinish()
				.toString(), "Wed May 07 10:39:00 BST 2008");

		Assert.assertEquals(task3.getStart()
				.toString(), "Mon May 05 09:00:00 BST 2008");
		Assert.assertEquals(task3.getPlannedFinish()
				.toString(), "Wed May 07 10:39:00 BST 2008");

		Assert.assertEquals(task2.getStart()
				.toString(), "Mon May 05 09:00:00 BST 2008");
		Assert.assertEquals(task2.getPlannedFinish()
				.toString(), "Wed May 07 10:39:00 BST 2008");

	}

	@Test(enabled = false)
	public void fixedDuration() throws PersistenceReferenceException {
		// straightforward, first priority task fixedWork , second fixed
		// duration
		BaseTask task1 = createAbstractTask("t1");
		BaseTask task2 = createAbstractTask("t2");

		leveller.addCandidate(task1);
		leveller.addCandidate(task2);

		task1.assignResource(resources[0], 1);
		task2.assignResource(resources[0], 1);

		task1.setPriority(1000);
		task2.setPriority(500);
		task2.setFixedDuration(true);
		task2.setDuration(1.5);

		Calendar cal = new GregorianCalendar();
		// Monday 5th May
		cal.set(2008, 4, 5);
		leveller.setLevelDate(cal.getTime());
		leveller.level();
		// ((IndividualResource) resources[0]).setProfile(leveller.getLevelDate(), 100);

		// first task should go to Wednesday
		Assert.assertEquals(task1.getStart()
				.toString(), "Mon May 05 09:00:00 BST 2008");
		Assert.assertEquals(task1.getPlannedFinish()
				.toString(), "Wed May 07 10:39:00 BST 2008");
		// second task should start Thursday 9.00, as there isn't sufficient
		// time
		// left for 100% allocation on Monday. It should plannedFinish half way through
		// Friday (so 210 mins into Friday)
		Assert.assertEquals(task2.getStart()
				.toString(), "Thu May 08 09:00:00 BST 2008");
		Assert.assertEquals(task2.getPlannedFinish()
				.toString(), "Fri May 09 12:29:00 BST 2008");

	}

	public void bookFullTaskFixedWorkOnly() throws ResourceAssignmentException, PersistenceReferenceException {

		BaseTask task = createAbstractTask("rt", 1000);
		task.setWorkRemaining(1000);
		task.assignResource(resources[0], 1);
		Q3Calendar cal = new Q3Calendar();
		cal.set(2008, 4, 5); // a Monday
		leveller.setLevelDate(cal.getTime());
		// ((IndividualResource) resources[0]).setProfile(leveller.getLevelDate(), 100);

		leveller.bookFullTask(task);
		Assert.assertTrue(task.isFullyAllocated());
		// correct plannedFinish time - 2 days at full allocation takes up 900
		// then there's 100 left to be done from 9 am on the third day
		IndividualResource ir = (IndividualResource) task.getAssignedResource();
		Assert.assertEquals(ir.getTotalEffortBooked(), 1000);
		Assert.assertEquals(ir.timeBooked(cal.getTime()), 450);
		cal.incDay();
		Assert.assertEquals(ir.timeBooked(cal.getTime()), 450);
		cal.incDay();
		Assert.assertEquals(ir.timeBooked(cal.getTime()), 100);
		Assert.assertEquals(sdf.format(task.getStart()), "05 May 08 09:00:00");
		Assert.assertEquals(sdf.format(task.getPlannedFinish()), "07 May 08 10:39:00");
	}

	@Test(enabled = false)
	public void bookFixedDurationTask() throws ResourceAssignmentException, PersistenceReferenceException {
		connection.openSession();
		BaseTask task = new BaseTask(connection);
		task.assignResource(resources[0], 1);
		task.setFixedDuration(true);
		task.setDuration(2);
		Calendar cal = new GregorianCalendar();
		cal.set(2008, 4, 5);
		leveller.setLevelDate(cal.getTime());
		// ((IndividualResource) resources[0]).setProfile(leveller.getLevelDate(), 100);

		leveller.bookFullTask(task);
		Assert.assertEquals(sdf.format(task.getStart()), "05 May 08 09:00:00");
		Assert.assertEquals(sdf.format(task.getPlannedFinish()), "06 May 08 16:29:00");
		connection.closeSession();
	}

	public void resourceNotAssigned() throws CycleDetectedException, ChangeInvalidException, PersistenceReferenceException {
		BaseTask st = createAbstractTask("sum");
		BaseTask rt = createAbstractTask("rt", 100);
		st.save();
		rt.setParentTask(st);
		rt.setWorkRemaining(1000);
		rt.assignResource(resources[0], 0);
		leveller.addCandidate(st);
		leveller.level();
	}

	/**
	 * Duration is not a whole number
	 * 
	 * @throws ResourceAssignmentException
	 * @throws PersistenceReferenceException
	 */
	@Test(enabled = false)
	public void bookFixedDurationTask_partDay() throws ResourceAssignmentException, PersistenceReferenceException {
		BaseTask task = createAbstractTask("RT", 1000);
		task.assignResource(resources[0], 1);
		task.setFixedDuration(true);
		task.setDuration(2.5);
		task.setName("bookFixedDurationTask_partDay");
		task.save();
		Q3Calendar cal = new Q3Calendar();
		cal.set(2008, 4, 5);
		leveller.setLevelDate(cal.getTime());
		// ((IndividualResource) resources[0]).setProfile(leveller.getLevelDate(), 100);

		leveller.bookFullTask(task);
		Resource r = task.getAssignedResource();
		Assert.assertEquals(r.timeBooked(cal.getTime()), 450);
		cal.incDay();
		Assert.assertEquals(r.timeBooked(cal.getTime()), 450);
		cal.incDay();
		Assert.assertEquals(r.timeBooked(cal.getTime()), 225);
		Assert.assertEquals(sdf.format(task.getStart()), "05 May 08 09:00:00");
		Assert.assertEquals(sdf.format(task.getPlannedFinish()), "07 May 08 12:44:00");
	}

	@Test(enabled = false)
	public void bookFixedDurationTask_bookingConflict() throws ResourceAssignmentException, PersistenceReferenceException {
		BaseTask task = createAbstractTask("RT", 1000);
		task.assignResource(resources[0], 1);
		task.setFixedDuration(true);
		task.setDuration(2.5);
		task.setName("bookFixedDurationTask_bookingConflict");
		task.save();
		Q3Calendar cal = new Q3Calendar();
		cal.set(2008, 4, 5);

		leveller.setLevelDate(cal.getTime());
		// ((IndividualResource) resources[0]).setProfile(leveller.getLevelDate(), 100);
		cal.incDay(); // put booking conflict on 2nd day
		task.getAssignedResource()
				.bookEffort(20, cal.getTime(), task);
		leveller.bookFullTask(task);

		// Tuesday was booked, so shouldn't start till Wednesday
		Assert.assertEquals(sdf.format(task.getStart()), "07 May 08 09:00:00");
		// half day is now Friday, so shorter
		Assert.assertEquals(sdf.format(task.getPlannedFinish()), "09 May 08 12:29:00");

	}

	/**
	 * When an adjustment has been made to the base calendar which prevents a booking being made, the task should continue in the same way
	 * as it would over a weekend - no work is done but the task is considered continuous
	 * 
	 * @throws ResourceAssignmentException
	 * @throws PersistenceReferenceException
	 */
	@Test(enabled = false)
	public void bookFixedDurationTask_holiday() throws ResourceAssignmentException, PersistenceReferenceException {
		connection.openSession();
		BaseTask task = new BaseTask(connection);
		task.assignResource(resources[0], 1);
		task.setFixedDuration(true);
		task.setDuration(2.5);
		task.setName("bookFixedDurationTask_holiday");
		Calendar cal = new GregorianCalendar();
		cal.set(2008, 4, 5);
		leveller.setLevelDate(cal.getTime());
		// ((IndividualResource) resources[0]).setProfile(leveller.getLevelDate(), 100);

		// put public on 2nd day
		Calendar publicHoliday = new GregorianCalendar();
		publicHoliday.set(2008, 4, 6);
		leveller.getBaseCalendar()
				.addAdjustment(publicHoliday.getTime(), true, 0);

		leveller.bookFullTask(task);

		// Tuesday was a base calendar "holiday" , so the Tuesday will be
		// skipped
		// but the task considered continuous

		Assert.assertEquals(sdf.format(task.getStart()), "05 May 08 09:00:00");
		// half day is now Friday, so shorter
		Assert.assertEquals(sdf.format(task.getPlannedFinish()), "08 May 08 12:44:00");
		connection.closeSession();
	}

	/**
	 * Predecessor holds up a task because it isn't finished. Test by making successor higher priority using the same resource
	 * 
	 * @throws PersistenceReferenceException
	 */
	public void predecessorDelay() throws PersistenceReferenceException {
		// 450 minutes is standard working day Mon-Fri
		BaseTask rt1 = createAbstractTask("predecessor", 450);
		BaseTask rt2 = createAbstractTask("successor", 450);
		rt2.addPredecessor(rt1);
		BaseTask rt3 = createAbstractTask("standalone med priority", 450);
		rt1.assignResource(resources[0], 1);
		rt2.assignResource(resources[0], 1);
		rt3.assignResource(resources[0], 1);
		// set to lowest priority causing delay to rt2
		rt1.setPriority(100);
		// should be higher priority than rt1 but is dependent on it
		rt2.setPriority(1000);
		// should be second but because of dependency will be done first
		rt3.setPriority(200);

		Calendar cal = new GregorianCalendar();
		// 5th May is a Monday
		cal.set(2008, 4, 5);
		leveller.setLevelDate(cal.getTime());
		logger.info("Level date set to " + leveller.getLevelDate());

		leveller.addCandidate(rt1);
		leveller.addCandidate(rt2);
		leveller.addCandidate(rt3);
		leveller.level();

		Assert.assertEquals(sdf.format(rt3.getStart()), "05 May 08 09:00:00");
		Assert.assertEquals(sdf.format(rt1.getStart()), "06 May 08 09:00:00");
		Assert.assertEquals(sdf.format(rt2.getStart()), "07 May 08 09:00:00");

	}

	/**
	 * Uses UoB MasterPlan as a test source, importing from XML and then levelling. Obviously therefore requires import to work, but does
	 * also add a bit of testing of the import routine
	 * 
	 * @throws PersistenceReferenceException
	 */
	@Test(enabled = false, groups = { "heapEater" })
	public void bigLevel() throws PersistenceReferenceException {

		ImportAction ia = new ImportAction();
		ia.setImportDb(connection, false);
		ia.run();
		// logger.info(connection.isOpen());
		// connection.open();
		Model.setConnection(connection);
		List<Class<? extends DomainObject>> taskClasses = new ArrayList<Class<? extends DomainObject>>();
		taskClasses.add(BaseTask.class);
		Model.taskManager()
				.setRoot((BaseTask) connection.taskService()
						.findFirstByName(taskClasses, "Master Plan"));
		// stop database from being updated - takes too long in test
		Model.level(null);
		TaskStatusReport tsr = new TaskStatusReport();
		tsr.setLevelDate(Model.getLevelDate());
		Model.taskManager()
				.getRoot()
				.reportStatus(tsr);
		logger.info(">>>>>>>>>>>> TSR >>>>>>>>>>>>>");
		StringBuffer s = new StringBuffer();
		tsr.output(s, 0);
		System.out.print(s.toString());
		System.out.println("<<<<<<<<<<<<<<<<<<<<<<<<");
		TaskAnalysisResult tar;

		// check report entries

		tar = TaskAnalysisResult.NOT_RESOURCED;
		System.out.println(tar + "  " + tsr.detail(tar));
		Assert.assertEquals(tsr.getResults(tar), 0);

		tar = TaskAnalysisResult.ZERO_ASSIGNMENT;
		System.out.println(tar + "  " + tsr.detail(tar));
		Assert.assertEquals(tsr.getResults(tar), 0);

		tar = TaskAnalysisResult.RESOURCE_GROUP_EMPTY;
		System.out.println(tar + "  " + tsr.detail(tar));
		Assert.assertEquals(tsr.getResults(tar), 0);

		tar = TaskAnalysisResult.NOT_PLANNED;
		System.out.println(tar + "  " + tsr.detail(tar));

		List<Task> detail = tsr.detail(tar);
		for (Task task : detail) {
			BaseTask rt = (BaseTask) task;
			System.out.println(rt.getTaskId());
		}
		Assert.assertEquals(tsr.getResults(tar), 0);

		tar = TaskAnalysisResult.PLANNED_TOO_EARLY;
		System.out.println(tar + "  " + tsr.detail(tar));
		Assert.assertEquals(tsr.getResults(tar), 0);
	}

	private BaseTask createAbstractTask(String name, int work) {
		BaseTask task = createStandardTask(name);
		task.setWorkRemaining(work);
		task.save();
		return task;
	}

	private BaseTask createAbstractTask(String name) {
		return createAbstractTask(name, 0);
	}

	private Resource createResource(int id, String name) throws PersistenceReferenceException {
		IndividualResource resource = new IndividualResource(connection);
		resource.setName(name);
		resource.save();
		resourcePool.addResource(resource);
		return resource;
	}

	private void buildPlan() throws CycleDetectedException, ChangeInvalidException, PersistenceReferenceException {
		task1 = createAbstractTask("Task:1");
		task11 = createAbstractTask("Task:11");
		task12 = createAbstractTask("Task:12");
		task111 = createAbstractTask("Task:111");
		task2 = createAbstractTask("Task:2");
		task21 = createAbstractTask("Task:21");
		task22 = createAbstractTask("Task:22");
		task211 = createAbstractTask("Task:211");
		task2111 = createAbstractTask("Task:2111");
		task3 = createAbstractTask("Task:3");

		task11.setParentTask(task1);
		task12.setParentTask(task1);
		task111.setParentTask(task11);
		task21.setParentTask(task2);
		task22.setParentTask(task2);
		task211.setParentTask(task21);
		task2111.setParentTask(task211);

		task12.addPredecessor(task111);
		task2111.addPredecessor(task22);
		// deleted - can't set this at summary level now
		// task22.setFixedDuration(true);

	}

	private void buildResources() throws PersistenceReferenceException {
		resourcePool = new ResourcePool(connection);

		String[] names = new String[] { "dsowerby", "mpaine", "rvafadari", "ahare", "gryder", "svanage", "ldiniro" };
		for (int i = 0; i < 7; i++) {
			resources[i] = createResource(i, names[i]);
		}
	}

	private void assignResources() {

	}

}
